#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>

static int major;
static struct class *hc_led_class;
struct gpio_desc *led_desc;

static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
	int  err;
	char val;
	err = copy_from_user(&val, buf, 1);
	gpiod_set_value(led_desc, val);  // val 只要非零就为有效状态
	return 0;
}

static int led_open (struct inode *node, struct file *filp)
{
	gpiod_set_value(led_desc, 0);
	return 0;
}

static struct file_operations led_ops = {
	.owner 		=	THIS_MODULE,
	.open 		=   led_open,
	.write 		=   led_write,
};

/*=============================platform_driver==============================*/
/* 匹配内核根据设备树生成的platform_device */
static int my_probe(struct platform_device *pdev)
{
	struct device dev = pdev->dev;

	/* 从设备树中获取gpio */
 	led_desc = gpiod_get(&dev, "led");

	/* 设置GPIO方向 */
	gpiod_direction_output(led_desc, 0);

	printk("my_probe run\n");
	
	return 0;
}

static int my_remove(struct platform_device *pdev)
{
	/* 释放GPIO */
	gpiod_put(led_desc);
	printk("my_remove run\n");

	return 0;
}

static struct of_device_id hc_led_match[] = {
	{.compatible = "hc-led"}, 
	{},
};

static struct platform_driver led_driver = {
	.probe		=	my_probe,	
	.remove		= 	my_remove,
	.driver		= {
		.name	= "led_platform_driver",
		.of_match_table = hc_led_match,
	},
};

/*=============================驱动出入口函数==============================*/
/* 驱动入口函数：insmod xx.ko 时会被调用 */
static int led_init(void)
{	
	major = register_chrdev(0, "led_driver", &led_ops);
	
	hc_led_class = class_create(THIS_MODULE, "led_class");
	if(IS_ERR(hc_led_class)){
		printk("hc_led_class create failed\n");
		return 1;
	}

	device_create(hc_led_class, NULL, MKDEV(major, 0), NULL, "led");

	platform_driver_register(&led_driver);

	return 0;
}

/* 驱动出口函数： rmmod xx.ko 时会被调用 */
static void led_exit(void)
{
	platform_driver_unregister(&led_driver);
	
	device_destroy(hc_led_class, MKDEV(major, 0));
	
	class_destroy(hc_led_class);
	
	unregister_chrdev(major, "led_driver");
	
	printk("hc_led driver exit\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");


